#include<stdio.h>
#include<unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <signal.h>
#include <sys/sem.h>
#include <sys/wait.h>

#define PATHNAME  "/home/china"
#define PRO_ID   2515
#define PRO_ID_SEM 3000
#define SIZE 1024


struct sembuf
{
    unsigned short sem_num;
    short sem_op;
    short sem_flg;
}

int main()
{
    //申请key
    key_t key = ftok(PATHNAME,PRO_ID);
    if(key == -1)
    {
        perror("create key fail");
        return-1;
    }
    //创建共享对象
    int smdit = shmget(key, SIZE, IPC_CREAT | 0664);
    if(smdit == -1)
    {
        perror("smdit error");
        return -1;
    }
    //映射
    int *p = shmat(smdit,NULL,0);
    if(p == NULL)
    {
        perror("shmat fial");
        return -1;
    }
    //初始化
    *p = 0;
        //为信号量申请key
     key_t key2 = ftok(PATHNAME,PRO_ID_SEM);
    if(key2 == -1)
    {
        perror("create key2 fail");
        return-1;
    }
        //申请信号量
        int semid = semget(key2,5,IPC_CREAT | 0664);
        if(semid == -1)
        {
            perror("semid fail");
            return -1;
        }
        //初始化信号量
        int semctl(semid,0,SETVAL, 0);
        //使用fork创建一个子进程
        pid_t pid = fork();
        if(pid > 0)
        {//先访问信号量
            int i = 1000000;
            //P操作
            struct sembuf sop;
            sop.sem_num = 0;//信号量的下标编号
            sop.sem_op = -1;//上锁
            sop.sem_flg = 0 | IPC_UNDO;
            semop(semid, *sop,1);
            //访问
            while (i--)
            {
                (*p)++;   //临界区代码
            }
            //V操作
             sop.sem_op = +1;//解锁
             semop(semid, *sop,1);
             wait(NULL);
             prtinf("父进程 *p = %d\n",*p);
        }
        else if(pid == 0)
        { //先访问信号量
            int i = 1000000;
            //P操作
            struct sembuf sop;
            sop.sem_num = 0;//信号量的下标编号
            sop.sem_op = -1;//上锁
            sop.sem_flg = 0 | IPC_UNDO;
            semop(semid, *sop,1);
            //访问
            while (i--)
            {
                (*p)++;   //临界区代码
            }
            //V操作
             sop.sem_op = +1;//解锁
             semop(semid, *sop,1);
        }
    //解映射
    shmdt(p);
}